﻿#pragma once

#include <EASTL/vector.h>
#include <glm.hpp>
#include <graphics/graphics_def.h>
#include <kfile.h>
#include <stdarg.h>
#include <xml_reader.h>

namespace ifire {
// 用于快捷方式
using MatrixList = eastl::vector<IMat>;
// 设置
inline void auto_size(MatrixList& list, size_t size){
  if (list.size() < size){
    list.resize(size);
  }
}

/// <summary>
/// 一个包装器，用于非性能敏感情况下的Vector处理。DirectXMath的StoreLoad太蛋痛了。
/// </summary>
struct XMVEC {
  IVec vec;

  // 通过XMVECTOR初始化
  XMVEC(FVec v) : vec(v) {}
  // 通过XMFLOAT初始化
  XMVEC(IVec2 v) : vec(XMLoadFloat2(&v)) {}
  XMVEC(IVec3 v) : vec(XMLoadFloat3(&v)) {}
  XMVEC(IVec4 v) : vec(XMLoadFloat4(&v)) {}

  // ------
  // 直接转化
  // ------
  IVec2 v2() { return IVec2(vec.m128_f32[0], vec.m128_f32[1]); }
  IVec3 v3() { return IVec3(vec.m128_f32[0], vec.m128_f32[1], vec.m128_f32[2]); }
  IVec4 v4() { return IVec4(vec.m128_f32[0], vec.m128_f32[1], vec.m128_f32[2], vec.m128_f32[3]); }
  IVec4 quat() { return IVec4(vec.m128_f32[0], vec.m128_f32[1], vec.m128_f32[2], vec.m128_f32[3]); }

  // ------
  // 运算转化
  // ------
  // 设项目中保存的是四元数，将其转化为欧拉角（角度）
  IVec3 to_euler() const;
  // 设项目中保存的是欧拉角（角度），将其转化为四元数
  IVec to_quat() const;
};

/// <summary>
/// 用于代表一个变换项目。命名的规则按照DirectXMath。混入其中^_^。
/// </summary>
struct Trans2 {
  IVec position;
  IVec rotation;

  // 初始化0wfh
  Trans2()
      : position(DirectX::XMVectorZero())
      , rotation(DirectX::XMVectorSet(0.0f, 0.0f, 0.0f, 1.0f)) {}
  // 通过XMFLOAT赋值
  Trans2(IVec3 _position, IVec4 _rotation)
      : position(DirectX::XMLoadFloat3(&_position))
      , rotation(DirectX::XMLoadFloat4(&_rotation)) {}
  // 通过XMVECTOR赋值
  Trans2(IVec _position, IVec _rotation)
      : position(_position), rotation(_rotation) {}
  // 拷贝构造函数（最有效率方式）
  Trans2(const Trans2& other)
      : position(other.position), rotation(other.rotation) {}
  // 使用一个矩阵初始化，从矩阵中提取项目
  Trans2(DirectX::FXMMATRIX mat);
  // 使用一个矩阵初始化，从矩阵中提取项目
  Trans2(const DirectX::XMFLOAT4X4& mat);

  // 得到可以表达的Position
  IVec3 GetPosition() const;
  // 得到Rotation的四元数
  IVec4 GetRotation() const;
  // 得到可以表达的Rotation，为欧拉角，以角度为单位
  IVec3 GetRotationEuler() const;

  // 进行减法
  Trans2 Minus(const Trans2& b) const;
  // 进行加法
  Trans2 Add(const Trans2& b) const;
  // 重置为单位矩阵
  void Reset();
  // 拼合为一个完整的矩阵
  IMat GetMatrix() const;
  // 打印项目，接受一个标头
  void Print(const char* format, ...) const;
};

/// <summary>
/// 用于代表一个变换项目。命名的规则按照DirectXMath。混入其中^_^。
/// </summary>
struct Trans3 {
  IVec position;
  IVec rotation;
  IVec scale;

  // 初始化
  Trans3();
  // 通过XMFLOAT赋值
  Trans3(IVec3 _position, IVec4 _rotation, IVec3 _scale);
  // 通过XMFLOAT赋值(Rotation做为欧拉角）
  Trans3(IVec3 _position, IVec3 _rotation, IVec3 _scale);
  // 通过一个Node获得
  Trans3(const ikit::XmlNode& node);
  // 通过XMVECTOR赋值
  Trans3(IVec _position, IVec _rotation, IVec _scale);
  // 拷贝构造函数（最有效率方式）
  Trans3(const Trans3& other);
  // 使用一个矩阵初始化，从矩阵中提取项目
  Trans3(FMat mat);
  // 使用一个矩阵初始化，从矩阵中提取项目
  Trans3(FMat4 mat);

  // 得到可以表达的Position
  IVec3 GetPosition() const;
  // 得到Rotation的四元数
  IVec4 GetRotation() const;
  // 得到可以表达的Rotation，为欧拉角，以角度为单位
  IVec3 GetRotationEuler() const;
  // 得到可以表达的Scale
  IVec3 GetScale() const;

  // 进行减法
  Trans3 Minus(const Trans3& b) const;
  // 进行加法
  Trans3 Add(const Trans3& b) const;
  // 重置为单位矩阵
  void Reset();
  // 拼合为一个完整的矩阵
  IMat GetMatrix() const;

  // 打印项目，接受一个标头
  void Print(const char* format, ...) const;
  // 打印项目到文件，接受一个标头
  void Print(ikit::file_printer& f, const char* format, ...) const;

  static Trans3 EMPTY;
};

} // namespace ifire